﻿using System;
using System.Text;
using System.IO;
using System.Security.Cryptography;


namespace Light.Utility.Security
{

    /// <summary>
    /// 可逆加密解密类
    /// </summary>
    public class ReversibleCryptor
    {

        /// <summary>
        /// RC2加密
        /// </summary>
        /// <param name="data">明文</param>
        /// <param name="key">密钥（长度大于4）</param>
        /// <returns>密文</returns>
        public static string Encrypt(string data, string key)
        {
            return EncryptData(data, key, "ini vect", EncryptionAlgorithm.Rc2);
        }

        /// <summary>
        /// RC2解密
        /// </summary>
        /// <param name="cipherText">密文</param>
        /// <param name="key">密钥（长度大于4）</param>
        /// <returns>明文</returns>
        public static string Decrypt(string cipherText, string key)
        {
            return DecryptData(cipherText, key, "ini vect", EncryptionAlgorithm.Rc2);
        }


        /// <summary>
        /// 加密数据
        /// </summary>
        /// <param name="plainstr">要加密的字符串</param>
        /// <param name="ASCIIKey">密钥</param>
        /// <param name="ASCIIInitializationVector">初始向量</param>
        /// <param name="algorithm">加密算法</param>
        /// <returns></returns>
        public static string EncryptData(string plainstr, string ASCIIKey, string ASCIIInitializationVector, EncryptionAlgorithm algorithm)
        {
            try
            {
                byte[] IV = null;           //初始向量
                byte[] cipherText = null;   //密文
                byte[] key = null;          //密钥
                Encryptor enc = new Encryptor(algorithm);//EncryptionAlgorithm.Des);
                byte[] plainText = Encoding.UTF8.GetBytes(plainstr);
                key = Encoding.ASCII.GetBytes(ASCIIKey);
                if (ASCIIInitializationVector != null)
                {
                    IV = Encoding.ASCII.GetBytes(ASCIIInitializationVector);
                    enc.IV = IV;
                }

                #region
                //if ((EncryptionAlgorithm.TripleDes == algorithm) || (EncryptionAlgorithm.Rijndael == algorithm))
                //{
                //    key = Encoding.ASCII.GetBytes(ASCIIKey);//?Key

                //    //if (EncryptionAlgorithm.Rijndael == algorithm)
                //    //{

                //    //    if (ASCIIInitializationVector != null)
                //    //    {
                //    //        IV = Encoding.ASCII.GetBytes(ASCIIInitializationVector);
                //    //    }
                //    //}
                //    //else
                //    //{
                //    //    if (ASCIIInitializationVector != null)
                //    //    {
                //    //        IV = Encoding.ASCII.GetBytes(ASCIIInitializationVector);
                //    //    }
                //    //}
                //}
                //else
                //{
                //    //Des 仅使用 8 字节的密钥。其他使用长度可变的密钥。
                //    key = Encoding.ASCII.GetBytes(ASCIIKey);
                //    if (ASCIIInitializationVector != null)
                //    {
                //        IV = Encoding.ASCII.GetBytes(ASCIIInitializationVector);
                //    }
                //}
                #endregion

                cipherText = enc.Encrypt(plainText, key);
                string str = Bytes2StrAccordingPosition(cipherText);
                return str;
            }
            catch (Exception ex)
            {
                return plainstr;
                //return "请输入正确的加密密钥：" + ex.Message;
            }
        }

        private static string Bytes2StrAccordingPosition(byte[] cbytes)
        {
            string str = "";
            for (int i = 0; i < cbytes.Length; i++)
            {
                str = str + Convert.ToChar(cbytes[i]);
            }
            return str;
        }

        private static byte[] Str2BytesAccordingPositon(string str)
        {
            char[] strchars = str.ToCharArray();
            byte[] bytes = new byte[str.Length];
            for (int i = 0; i < str.Length; i++)
            {
                bytes[i] = Convert.ToByte(strchars[i]);
            }
            return bytes;
        }

        /// <summary>
        /// 解密
        /// </summary>
        /// <param name="cipherText">密文</param>
        /// <param name="ASCIIKey">密钥</param>
        /// <param name="ASCIIInitializationVector">初始向量</param>
        /// <param name="algorithm">加密算法</param>
        /// <returns></returns>
        public static string DecryptData(string cipherText, string ASCIIKey, string ASCIIInitializationVector, EncryptionAlgorithm algorithm)
        {

            try
            {
                byte[] IV = Encoding.ASCII.GetBytes(ASCIIInitializationVector);
                byte[] key = Encoding.ASCII.GetBytes(ASCIIKey);


                Decryptor dec = new Decryptor(algorithm);
                if (ASCIIInitializationVector != null)
                {
                    dec.IV = IV;
                }
                // 继续并解密。
                byte[] cipherTextbytes = Str2BytesAccordingPositon(cipherText);
                byte[] plainText = dec.Decrypt(cipherTextbytes, key);

                return Encoding.UTF8.GetString(plainText);
            }
            catch (Exception ex)
            {
                return cipherText;
                //return "密钥不正确，解密失败！";

            }
        }




    }

    /// <summary>
    /// 加密算法(枚举)
    /// </summary>
    public enum EncryptionAlgorithm
    {

        /// <summary>
        /// 8 字节
        /// </summary>
        Des = 1,
        /// <summary>
        /// 长度可变（大于4)
        /// </summary>
        Rc2,
        /// <summary>
        /// 16 字节
        /// </summary>
        Rijndael,
        /// <summary>
        /// 16 或 24 字节
        /// </summary>
        TripleDes

    };

    /// <summary>
    /// 解密器
    /// </summary>
    class Decryptor
    {

        private DecryptTransformer transformer;
        private byte[] initVec;


        public Decryptor(EncryptionAlgorithm algId)
        {
            transformer = new DecryptTransformer(algId);
        }

        public byte[] Decrypt(byte[] bytesData, byte[] bytesKey)
        {
            //为解密数据设置内存流。
            MemoryStream memStreamDecryptedData = new MemoryStream();

            //传递初始化向量。
            if (initVec != null)
            {
                transformer.IV = initVec;
            }
            ICryptoTransform transform = transformer.GetCryptoServiceProvider(bytesKey);
            CryptoStream decStream = new CryptoStream(memStreamDecryptedData,
             transform,
             CryptoStreamMode.Write);
            try
            {
                decStream.Write(bytesData, 0, bytesData.Length);
            }
            catch (Exception ex)
            {
                throw new Exception("将加密数据写入流时出错： \n" + ex.Message);
            }
            decStream.FlushFinalBlock();
            decStream.Close();
            // 发送回数据。
            return memStreamDecryptedData.ToArray();
        } //end Decrypt

        public byte[] IV
        {
            set { initVec = value; }
        }


    }


    class DecryptTransformer
    {

        private EncryptionAlgorithm algorithmID;
        private byte[] initVec;


        internal DecryptTransformer(EncryptionAlgorithm deCryptId)
        {
            algorithmID = deCryptId;
        }
        internal ICryptoTransform GetCryptoServiceProvider(byte[] bytesKey)
        {
            // Pick the provider.
            switch (algorithmID)
            {
                case EncryptionAlgorithm.Des:
                    {
                        DES des = new DESCryptoServiceProvider();
                        des.Mode = CipherMode.CBC;
                        des.Key = bytesKey;
                        if (initVec != null)
                        {
                            des.IV = initVec;
                        }
                        return des.CreateDecryptor();
                    }
                case EncryptionAlgorithm.TripleDes:
                    {
                        TripleDES des3 = new TripleDESCryptoServiceProvider();
                        des3.Mode = CipherMode.CBC;
                        return des3.CreateDecryptor(bytesKey, initVec);
                    }
                case EncryptionAlgorithm.Rc2:
                    {
                        RC2 rc2 = new RC2CryptoServiceProvider();
                        rc2.Mode = CipherMode.CBC;
                        return rc2.CreateDecryptor(bytesKey, initVec);
                    }
                case EncryptionAlgorithm.Rijndael:
                    {
                        Rijndael rijndael = new RijndaelManaged();
                        rijndael.Mode = CipherMode.CBC;
                        return rijndael.CreateDecryptor(bytesKey, initVec);
                    }
                default:
                    {
                        throw new CryptographicException("算法 ID '" + algorithmID +
                         "' 不支持。");
                    }
            }
        } //end GetCryptoServiceProvider
        internal byte[] IV
        {
            set { initVec = value; }
        }
    }

    /// <summary>
    /// 加密器
    /// </summary>
    class Encryptor
    {

        private EncryptTransformer transformer;
        private byte[] initVec;
        private byte[] encKey;


        public Encryptor(EncryptionAlgorithm algId)
        {
            transformer = new EncryptTransformer(algId);
        }

        public byte[] Encrypt(byte[] bytesData, byte[] bytesKey)
        {
            //设置将保存加密数据的流。
            MemoryStream memStreamEncryptedData = new MemoryStream();
            if (initVec != null)
            {
                transformer.IV = initVec;
            }
            ICryptoTransform transform = transformer.GetCryptoServiceProvider
             (bytesKey);
            CryptoStream encStream = new CryptoStream(memStreamEncryptedData,
             transform,
             CryptoStreamMode.Write);
            try
            {
                //加密数据，并将它们写入内存流。
                encStream.Write(bytesData, 0, bytesData.Length);
            }
            catch (Exception ex)
            {
                throw new Exception("将加密数据写入流时 出错： \n" + ex.Message);
            }
            //为客户端进行检索设置初始化向量和密钥
            encKey = transformer.Key;
            if (transformer.IV != null)
            {
                initVec = transformer.IV;
            }
            encStream.FlushFinalBlock();
            encStream.Close();

            //发送回数据。
            return memStreamEncryptedData.ToArray();
        }

        public byte[] IV
        {
            get { return initVec; }
            set { initVec = value; }
        }

        public byte[] Key
        {
            get { return encKey; }
        }


    }

    class EncryptTransformer
    {


        private EncryptionAlgorithm algorithmID;
        private byte[] initVec;
        private byte[] encKey;

        internal byte[] IV
        {
            get { return initVec; }
            set { initVec = value; }
        }
        internal byte[] Key
        {
            get { return encKey; }
        }


        internal EncryptTransformer(EncryptionAlgorithm algId)
        {
            //保存正在使用的算法。
            algorithmID = algId;
        }

        internal ICryptoTransform GetCryptoServiceProvider(byte[] bytesKey)
        {
            // 选取提供程序。
            switch (algorithmID)
            {
                case EncryptionAlgorithm.Des:
                    {
                        DES des = new DESCryptoServiceProvider();
                        des.Mode = CipherMode.CBC;

                        // 查看是否提供了密钥
                        if (bytesKey == null)
                        {
                            encKey = des.Key;
                        }
                        else
                        {
                            des.Key = bytesKey;
                            encKey = des.Key;
                        }
                        // 查看客户端是否提供了初始化向量
                        if (initVec == null)
                        {
                            initVec = des.IV;
                        }
                        else
                        {
                            des.IV = initVec;
                        }
                        return des.CreateEncryptor();
                    }
                case EncryptionAlgorithm.TripleDes:
                    {
                        TripleDES des3 = new TripleDESCryptoServiceProvider();
                        des3.Mode = CipherMode.CBC;
                        // See if a key was provided
                        if (null == bytesKey)
                        {
                            encKey = des3.Key;
                        }
                        else
                        {
                            des3.Key = bytesKey;
                            encKey = des3.Key;
                        }
                        // 查看客户端是否提供了初始化向量
                        if (null == initVec)
                        { //是，让算法创建一个
                            initVec = des3.IV;
                        }
                        else
                        { //不，将它提供给算法。
                            des3.IV = initVec;
                        }
                        return des3.CreateEncryptor();
                    }
                case EncryptionAlgorithm.Rc2:
                    {
                        RC2 rc2 = new RC2CryptoServiceProvider();
                        rc2.Mode = CipherMode.CBC;
                        // 测试是否提供了密钥
                        if (null == bytesKey)
                        {
                            encKey = rc2.Key;
                        }
                        else
                        {
                            rc2.Key = bytesKey;
                            encKey = rc2.Key;
                        }
                        // 查看客户端是否提供了初始化向量
                        if (null == initVec)
                        { //是，让算法创建一个
                            initVec = rc2.IV;
                        }
                        else
                        { //不，将它提供给算法。
                            rc2.IV = initVec;
                        }
                        return rc2.CreateEncryptor();
                    }
                case EncryptionAlgorithm.Rijndael:
                    {
                        Rijndael rijndael = new RijndaelManaged();
                        rijndael.Mode = CipherMode.CBC;
                        // 测试是否提供了密钥
                        if (null == bytesKey)
                        {
                            encKey = rijndael.Key;
                        }
                        else
                        {
                            rijndael.Key = bytesKey;
                            encKey = rijndael.Key;
                        }
                        // 查看客户端是否提供了初始化向量
                        if (null == initVec)
                        { //是，让算法创建一个
                            initVec = rijndael.IV;
                        }
                        else
                        { //不，将它提供给算法。
                            rijndael.IV = initVec;
                        }
                        return rijndael.CreateEncryptor();
                    }
                default:
                    {
                        throw new CryptographicException("算法 ID '" + algorithmID +
                         "' 不受支持。");
                    }
            }
        }


    }




}

#region 使用示例


//public void Des(string data, string key)
//{
//    string plaintext = data;
//    string encodestr = CryptograpLight.EncryptData(plaintext, key, "ini vect", EncryptionAlgorithm.Des);
//    string decodestr = CryptograpLight.DecryptData(encodestr, key, "ini vect", EncryptionAlgorithm.Des);
//    string result = plaintext == decodestr ? " 1" : " 0";
//    MessageBox.Show(result);


//}

//public void RC2()
//{
//    string plaintext = "haha";
//    string encodestr = CryptograpLight.EncryptData(plaintext, "password", "ini vect", EncryptionAlgorithm.Rc2);
//    string decodestr = CryptograpLight.DecryptData(encodestr, "password", "ini vect", EncryptionAlgorithm.Rc2);
//    string result = plaintext == decodestr ? " 1" : " 0";
//    MessageBox.Show(result);

//}

//public void TripleDes()
//{
//    string plaintext = "haha";
//    string encodestr = CryptograpLight.EncryptData(plaintext, "password12345678", "init vec", EncryptionAlgorithm.TripleDes);
//    string decodestr = CryptograpLight.DecryptData(encodestr, "password12345678", "init vec", EncryptionAlgorithm.TripleDes);
//    string result = plaintext == decodestr ? " 1" : " 0";
//    MessageBox.Show(result);

//}

//public void Rijndael()
//{
//    string plaintext = "haha";
//    string encodestr = CryptograpLight.EncryptData(plaintext, "password12345678", "password12345679", EncryptionAlgorithm.Rijndael);
//    string decodestr = CryptograpLight.DecryptData(encodestr, "password12345678", "password12345679", EncryptionAlgorithm.Rijndael);
//    string result = plaintext == decodestr ? " 1" : " 0";
//    MessageBox.Show(result);

//}

#endregion 使用示例